TITLE 11/22/83 BIOS
.XLIST
INCLUDE DSEG.SRC
INCLUDE POSTEQU.SRC
INCLUDE IAPX286.MAC
.LIST
INCLUDE SEGMENT.SRC
EXTRN	C8042:NEAR
EXTRN	OBF_42:NEAR
EXTRN	DDS:NEAR
EXTRN	PRT_HEX:NEAR
EXTRN	D1:NEAR
EXTRN	D2:NEAR
EXTRN	P_MSG:NEAR
EXTRN	D2A:NEAR
EXTRN	PRT_SEG:NEAR
EXTRN	PROC_SHUTDOWN:NEAR
EXTRN	CM3:NEAR
EXTRN	E_MSG:NEAR

PUBLIC	MEMORY_SIZE_DETERMINE_1
PUBLIC	EQUIPMENT_1
PUBLIC	NMI_INT_1
PUBLIC	SET_TOD

;--- INT 12 ----------------------------------------------------:
; MEMORY_SIZE_DETERMINE 					:
;	THIS ROUTINE RETURNS THE AMOUNT OF MEMORY IN THE	:
;	SYSTEM AS DETERMINED BY THE POST ROUTINES.		:
;	NOTE THAT THE SYSTEM MAY NOT BE ABLE TO USE I/O MEMORY	:
;	UNLESS THERE IS A FULL COMPLEMENT OF 512K BYTES ON THE	:
;	PLANAR. 						:
; INPUT 							:
;	NO REGISTERS						:
;	THE MEMORY_SIZE VARIABLE IS SET DURING POWER ON 	:
;	DIAGNOSTICS ACCORDING TO THE FOLLOWING ASSUMPTIONS:	:
;								:
;	1. CONFIGURATION RECORD IN NON-VOLATILE MEMORY		:
;	   EQUALS THE ACTUAL MEMORY SIZE INSTALLED.		:
;								:
;	2. ALL INSTALLED MEMORY IS FUNCTIONAL.	IF THE		:
;	   MEMORY TEST DURING POST INDICATES LESS, THEN THIS	:
;	   VALUE BECOMES THE DEFAULT.  IF NON-VOLATILE MEMORY	:
;	   IS NOT VALID (NOT INITIALIZED OR BATTERY FAILURE)	:
;	   THEN ACTUAL MEMORY DETERMINED BECOMES THE DEFAULT.	:
;								:
;	3. ALL MEMORY FROM 0 TO 640K MUST BE CONTIGUOUS.	:
;								:
; OUTPUT							:
;	(AX) = NUMBER OF CONTIGUOUS 1K BLOCKS OF MEMORY 	:
;---------------------------------------------------------------:
	ASSUME	CS:CODE,DS:DATA

MEMORY_SIZE_DETERMINE_1  PROC FAR
	STI			; INTERRUPTS BACK ON
	PUSH	DS		; SAVE SEGMENT
	CALL	DDS		; ESTABLISH ADDRESSING
	MOV	AX,MEMORY_SIZE	; GET VALUE
	POP	DS		; RECOVER SEGMENT
	IRET			; RETURN TO CALLER
MEMORY_SIZE_DETERMINE_1 ENDP

;--- INT 11 ----------------------------------------------------:
; EQUIPMENT DETERMINATION					:
;	THIS ROUTINE ATTEMPTS TO DETERMINE WHAT OPTIONAL	:
;	DEVICES ARE ATTACHED TO THE SYSTEM.			:
; INPUT 							:
;	NO REGISTERS						:
;	THE EQUIP_FLAG VARIABLE IS SET DURING THE POWER ON	:
;	DIAGNOSTICS USING THE FOLLOWING HARDWARE ASSUMPTIONS:	:
;	PORT 3FA = INTERRUPT ID REGISTER OF 8250 (PRIMARY)	:
;	     2FA = INTERRUPT ID REGISTER OF 8250 (SECONDARY)	:
;		BITS 7-3 ARE ALWAYS 0				:
;	PORT 378 = OUTPUT PORT OF PRINTER (PRIMARY)		:
;	     278 = OUTPUT PORT OF PRINTER (SECONDARY)		:
;	     3BC = OUTPUT PORT OF PRINTER (MONO-PRINTER)	:
; OUTPUT							:
;	(AX) IS SET, BIT SIGNIFICANT, TO INDICATE ATTACHED I/O	:
;	BIT 15,14 = NUMBER OF PRINTERS ATTACHED 		:
;	BIT 13,12 NOT USED					:
;	BIT 11,10,9 = NUMBER OF RS232 CARDS ATTACHED		:
;	BIT 8 = NOT USED					:
;	BIT 7,6 = NUMBER OF DISKETTE DRIVES			:
;		00=1, 01=2 ONLY IF BIT 0 = 1			:
;	BIT 5,4 = INITIAL VIDEO MODE				:
;			00 - UNUSED				:
;			01 - 40X25 BW USING COLOR CARD		:
;			10 - 80X25 BW USING COLOR CARD		:
;			11 - 80X25 BW USING BW CARD		:
;								:
;	BIT 3 = NOT USED					:
;	BIT 2 = NOT USED					:
;	BIT 1 = MATH COPROCESSOR				:
;	BIT 0 = 1 (IPL DISKETTE INSTALLED)			:
;	NO OTHER REGISTERS AFFECTED				:
;---------------------------------------------------------------:
	ASSUME	CS:CODE,DS:DATA

EQUIPMENT_1	PROC FAR		; >>>  ENTRY POINT FOR ORG 0F84DH
	STI				; INTERRUPTS BACK ON
	PUSH	DS			; SAVE SEGMENT REGISTER
	CALL	DDS			; ESTABLISH ADDRESSING
	MOV	AX,EQUIP_FLAG		; GET THE CURRENT SETTINGS
	POP	DS			; RECOVER SEGMENT
	IRET				; RETURN TO CALLER
EQUIPMENT_1	ENDP
;-- INT 2 ------------------------------------------------------:
; NON-MASKABLE INTERRUPT ROUTINE (REAL MODE)			:
;	THIS ROUTINE WILL PRINT A "PARITY CHECK 1 OR 2" MESSAGE :
;	AND ATTEMPT TO FIND THE STORAGE LOCATION CONTAINING THE :
;	BAD PARITY.  IF FOUND, THE SEGMENT ADDRESS WILL BE	:
;	PRINTED.  IF NO PARITY ERROR CAN BE FOUND (INTERMITTENT :
;	READ PROBLEM) ?????<-WILL BE PRINTED WHERE THE ADDRESS	:
;	WOULD NORMALLY GO.					:
;								:
;	PARITY CHECK 1 = PLANAR BOARD MEMORY FAILURE.		:
;	PARITY CHECK 2 = OFF PLANAR BOARD MEMORY FAILURE.	:
;---------------------------------------------------------------:

NMI_INT_1 PROC	  NEAR
	ASSUME	DS:DATA
	PUSH	AX			; SAVE ORIGINAL CONTENTS OF (AX)
	IN	AL,MFG_PORT		; INCREMENT NMI COUNT
	INC	AL			;
	JMP	SHORT $+2		; IN DELAY
	OUT	MFG_PORT,AL		; SET COUNT

	IN	AL,PORT_B
	TEST	AL,PARITY_ERR		; PARITY CHECK?
	MOV	AH,AL			; SAVE PARITY STATUS
	JNZ	NMI_1
	JMP	D14			; NO, EXIT FROM ROUTINE
NMI_1:
;------- GET THE SWITCH SETTINGS

	MOV	AL,DIS_KBD		; DISABLE THE KEYBOARD
	CALL	C8042			;
	IN	AL,PORT_A		; FLUSH
	MOV	AL,READ_8042_INPUT	; GET THE SWITCH SETTINGS
	CALL	C8042			; ISSUE THE COMMAND
	CALL	OBF_42			; WAIT FOR OUTPUT BUFF FULL
	IN	AL,PORT_A		; GET THE SWITCH
	OUT	MFG_PORT,AL		; SAVE SWITCH

	MOV	DX,DATA
	MOV	DS,DX
	MOV	SI,OFFSET D1		; ADDR OF ERROR MSG
	TEST	AH,40H			; I/O PARITY CHECK
	JNZ	NMI_2			; DISPLAY ERROR MSG
	MOV	SI,OFFSET D2		; MUST BE PLANAR
NMI_2:
	MOV	AH,0			; INIT AND SET MODE FOR VIDEO
	MOV	AL,CRT_MODE
	INT	10H			; CALL VIDEO_IO PROCEDURE
	CALL	P_MSG			; PRINT ERROR MSG
;----- SEE IF LOCATION THAT CAUSED PARITY CHECK CAN BE FOUND
	MOV	AL,0FFH 		; MASK TRAP
	OUT	CMOS_PORT,AL
	IN	AL,PORT_B
	JMP	SHORT $+2		; IO DELAY
	OR	AL,RAM_PAR_OFF		; TOGGLE PARITY CHECK ENABLES
	OUT	PORT_B,AL
	JMP	SHORT $+2		; IO DELAY
	AND	AL,RAM_PAR_ON
	OUT	PORT_B,AL
	MOV	BX,MEMORY_SIZE		; GET MEMORY SIZE WORD
	CLD				; SET DIR FLAG TO INCREMENT
	SUB	DX,DX			; POINT DX AT START OF MEM
NMI_LOOP:
	MOV	DS,DX
	MOV	ES,DX
	MOV	CX,4000H*2		; SET FOR 64KB SCAN
	SUB	SI,SI			; SET SI TO BE RELATIVE TO
					; START OF ES
	REP	LODSW			; READ 64KB OF MEMORY

	IN	AL,PORT_B		; SEE IF PARITY CHECK HAPPENED
	XCHG	AL,AH			; SAVE PARITY CHECK
	CMP	DX,4000H		; CHECK FOR END OF FIRST 256K
	JB	NMI_3
	CMP	DX,8000H		; CHECK ABOVE 512K
	JAE	NMI_4			; CHECK FOR IO CHECK
	IN	AL,MFG_PORT		; GET THE SWITCH SETTINGS
	TEST	AL,BASE_RAM		; CHECK FOR 2ND 256K ON PLANAR
	JZ	NMI_4			; GO IF NOT
NMI_3:	TEST	AH,PRTY_CHK		; CHECK FOR PARITY ERR
	JMP	NMI_5			; CONTINUE
NMI_4:	TEST	AH,IO_CHK		; TEST FOR IO ERROR
NMI_5:	JNZ	PRT_NMI 		; GO PRINT ADDRESS IF IT DID
	ADD	DX,1000H		; POINT TO NEXT 64K BLOCK
	SUB	BX,16D*4
	JNZ	NMI_LOOP
	MOV	SI,(OFFSET D2A) 	; PRINT ROW OF ????? IF PARITY
	CALL	P_MSG			; CHECK COULD NOT BE RE-CREATED
	CLI
	HLT				; HALT SYSTEM
PRT_NMI:
	MOV	DX,DS
	CALL	PRT_SEG 		; PRINT SEGMENT VALUE
	MOV	AL,'('                  ; PRINT (S)
	CALL	PRT_HEX
	MOV	AL,'S'
	CALL	PRT_HEX
	MOV	AL,')'
	CALL	PRT_HEX
	CLI				; HALT SYSTEM
	HLT
D14:
	MOV	AL,8FH			; TOGGLE NMI
	OUT	CMOS_PORT,AL		;
	JMP	SHORT $+2		; IO DELAY
	MOV	AL,0FH			;
	OUT	CMOS_PORT,AL		;
	POP	AX			; RESTORE ORIG CONTENTS OF AX
	IRET
NMI_INT_1 ENDP
PAGE
;----------------------------------------------------------------
;	THIS ROUTINE INITIALIZES THE TIMER DATA AREA IN THE	:
;	ROM BIOS DATA AREA.  IT IS CALLED BY THE POWER ON	:
;	ROUTINES.  IT CONVERTS HR:MIN:SEC FROM CMOS TO TIMER	:
;	TICS.  IF CMOS IS INVALID, TIMER DATA IS SET TO ZERO.	:
;----------------------------------------------------------------
;
; INPUT    NONE PASSED TO ROUTINE BY CALLER
;
; CMOS BYTES USED FOR SETUP
;
;	00	SECONDS
;	02	MINUTES
;	04	HOURS
;	0A	REGISTER A (UPDATE IN PROGRESS)
;	0E	CMOS VALID IF ZERO
;
; OUTPUT
;	TIMER_LOW
;	TIMER_HIGH
;	TIMER_OFL
;	ALL REGISTERS UNCHANGED
;
;------------------------------------------------------------------------
COUNTS_SEC	EQU	18
COUNTS_MIN	EQU	1092
COUNTS_HOUR	EQU	7		; 65543 - 65536
CMOS_ADR	EQU	70H
CMOS_DATA	EQU	71H
CMOS_VALID	EQU	0EH
CMOS_SECONDS	EQU	00H
CMOS_MINUTES	EQU	02H
CMOS_HOURS	EQU	04H
CMOS_REGA	EQU	0AH
UPDATE_TIMER	EQU	80H
SET_TOD PROC	NEAR
	PUSHA
	PUSH	DS
	ASSUME	DS:DATA
	MOV	AX,DATA 		; ESTABLISH SEGMENT
	MOV	DS,AX
	SUB	AX,AX
	MOV	TIMER_OFL,AL		; RESET TIMER ROLL OVER INDICATOR
	MOV	TIMER_LOW,AX		; AND TIMER COUNT
	MOV	TIMER_HIGH,AX
	MOV	AL,CMOS_VALID
	OUT	CMOS_ADR,AL		; CHECK CMOS VALIDITY
	JMP	SHORT $+2
	IN	AL,CMOS_DATA
	AND	AL,0C4H 		; BAD BATTERY, CHKSUM ERROR, CLOCK ERROR
	JNZ	POD_DONE		; CMOS NOT VALID -- TIMER SET TO ZERO
	SUB	CX,CX
UIP:	MOV	AL,CMOS_REGA
	OUT	CMOS_ADR,AL		; ACCESS REGISTER A
	JMP	SHORT $+2
	IN	AL,CMOS_DATA
	TEST	AL,UPDATE_TIMER
	JZ	READ_SEC
	LOOP	UIP
	JMP	POD_DONE		; CMOS CLOCK STUCK
READ_SEC:
	MOV	AL,CMOS_SECONDS
	OUT	CMOS_ADR,AL		; ACCESS SECONDS VALUE IN CMOS
	JMP	SHORT $+2
	IN	AL,CMOS_DATA

	CMP	AL,59H			; ARE THE SECONDS WITHIN LIMITS?
	JA	TOD_ERROR		; GO IF NOT

	CALL	CVT_BINARY		; CONVERT IT TO BINARY
	MOV	BL,COUNTS_SEC
	MUL	BL			; COUNT FOR SECONDS
	MOV	CX,AX
	MOV	AL,CMOS_MINUTES
	OUT	CMOS_ADR,AL		; ACCESS MINUTES VALUE IN CMOS
	JMP	SHORT $+2
	IN	AL,CMOS_DATA

	CMP	AL,59H			; ARE THE MINUTES WITHIN LIMITS?
	JA	TOD_ERROR		; GO IF NOT

	CALL	CVT_BINARY		; CONVERT IT TO BINARY
	MOV	BX,COUNTS_MIN
	MUL	BX			; COUNT FOR MINUTES
	ADD	AX,CX
	MOV	CX,AX
	MOV	AL,CMOS_HOURS
	OUT	CMOS_ADR,AL		; ACCESS HOURS VALUE IN CMOS
	JMP	SHORT $+2
	IN	AL,CMOS_DATA
	CMP	AL,23H			; ARE THE HOURS WITHIN LIMITS?
	JA	TOD_ERROR		; GO IF NOT
	CALL	CVT_BINARY		; CONVERT IT TO BINARY
	MOV	DX,AX
	MOV	BL,COUNTS_HOUR
	MUL	BL			; COUNT FOR HOURS
	ADD	AX,CX
	ADC	DX,0000H
	MOV	TIMER_HIGH,DX
	MOV	TIMER_LOW,AX
POD_DONE:
	CLI				; ** IO DELAY NOT REQUIRED **
	IN	AL,021H 		; BE SURE TIMER IS ENABLED
	AND	AL,0FEH
	OUT	021H,AL
	STI
	POP	DS
	POPA
	RET
TOD_ERROR:
	POP	DS			; RESTORE SEGMENT
	POPA				; RESTORE REGS
	MOV	SI,OFFSET CM3		; DISPLAY CLOCK ERROR
	CALL	E_MSG			;
	MOV	AL,DIAG_STATUS		; SET CLOCK ERROR
	OUT	CMOS_PORT,AL		;
	XCHG	AL,AH			; SAVE STATUS ADDRESS
	JMP	SHORT $+2		; IO DELAY
	IN	AL,CMOS_PORT+1		; GET THE CURRENT STATUS
	OR	AL,CMOS_CLK_FAIL	; SET NEW STATUS
	XCHG	AL,AH			; GET STATUS ADDR AND SAVE NEW STATUS
	OUT	CMOS_PORT,AL		;
	XCHG	AL,AH			;
	JMP	SHORT $+2		; IO DELAY
	OUT	CMOS_PORT+1,AL		;
	RET

SET_TOD ENDP

CVT_BINARY	PROC	NEAR
	MOV	AH,AL			; UNPACK 2 BCD DIGITS IN AL
	ISHR	AH,4
	AND	AL,0FH			; RESULT IS IN AX
	AAD				; CONVERT UNPACKED BCD TO BINARY
	RET
CVT_BINARY	ENDP
CODE	ENDS
	END
